/*
 * Copyright 2024 KylinSoft Co., Ltd.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <https://www.gnu.org/licenses/>.
 */

#include "utils.h"

#include <uuid/uuid.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <openssl/evp.h>

#include <iostream>
#include <cmath>
#include <regex>
#include <sstream>
#include <fstream>

namespace utils {

std::string generateUUID()
{
    uuid_t uuid;
    char uuid_str[37];

    uuid_generate_random(uuid);
    uuid_unparse(uuid, uuid_str);
    std::string id = uuid_str;

    return id;
}
//将vector中数据类型从float转变为double
std::vector<double> convertFloatToDouble(const std::vector<float>& floatVec) {
    std::vector<double> doubleVec;
    doubleVec.reserve(floatVec.size()); // 预留空间以避免不必要的重新分配

    for (float floatValue : floatVec) {//强制类型转换，最常用的就是static_cast,如果想消除const，volatile属性得用到const_cast(一般不要用)
        doubleVec.push_back(static_cast<double>(floatValue));
    }

    return doubleVec;
}

std::string base64Encode(const std::string& input) {
    BIO *bio, *b64;
    BUF_MEM *bufferPtr;

    b64 = BIO_new(BIO_f_base64());
    bio = BIO_new(BIO_s_mem());
    bio = BIO_push(b64, bio);

    BIO_write(bio, input.c_str(), input.length());
    BIO_flush(bio);

    BIO_get_mem_ptr(bio, &bufferPtr);
    BIO_set_close(bio, BIO_NOCLOSE);
    BIO_free_all(bio);

    return std::string(bufferPtr->data, bufferPtr->length);
}

std::string readImageFile(const std::string& filePath) {
    std::ifstream file(filePath, std::ios::binary);
    if (!file) {
        std::cerr << "Error opening file: " << filePath << std::endl;
        return "";
    }

    std::ostringstream oss;
    oss << file.rdbuf();
    return oss.str();
}

std::string encodeImageToBase64(const std::string& filePath) {
    std::string imageData = readImageFile(filePath);
    if (imageData.empty()) {
        std::cerr << "Failed to read image file: " << filePath << std::endl;
        return std::string();
    }

    std::string base64Data = base64Encode(imageData);

    return base64Data;
}


}

namespace math {
void normalize(std::vector<float> &vec)
{
    if (vec.empty()) {
        return;
    }

    float normNum = norm(vec);
    if (normNum == 0.0) {
        return;
    }

    for (int i = 0; i < vec.size(); ++i) {
        vec[i] = vec[i] / normNum;
    }
}

// 向量取模
float norm(const std::vector<float>& vec)
{
    float norm = 0.0f;
    for (const float& element : vec) {
        norm += element * element;
    }
    norm = std::sqrt(norm);

    return norm;
}

void normalizeTokens(std::vector<int64_t> &tokens, int length)
{
    if (tokens.size() == length) {
        return;
    } else if (tokens.size() > length) {
        tokens[length - 1] = tokens.back();
        tokens.resize(length);
        std::cerr << "Input tokens exceed " << length
                  << ", the tokens will be cropped" << std::endl;
    } else {
        tokens.resize(52, 0);
    }
}
} // namespace math


namespace text {

//去除多余的换行和空格、使用递归的方式进行文档切分
void applyRegex(std::string &text) {
    static const std::regex newlineRegex("\\n{3,}");
    static const std::regex spaceRegex("\\s");
    static const std::regex doubleNewlineRegex("\\n\\n");
    static const std::regex singlePunctuationRegex("([;；.!?。！？\\?])([^”’])");
    static const std::regex ellipsisRegex("(\\.{6})([^\"’”」』])");
    static const std::regex chineseEllipsisRegex("(\\…{2})([^\"’”」』])");
    static const std::regex endQuotePunctuationRegex("([;；!?。！？\\?][\"’”」』]{0,2})([^;；!?，。！？\\?])");

    text = std::regex_replace(text, newlineRegex, "\n");
    text = std::regex_replace(text, spaceRegex, " ");
    text = std::regex_replace(text, doubleNewlineRegex, "");
    text = std::regex_replace(text, singlePunctuationRegex, "$1\n$2");
    text = std::regex_replace(text, ellipsisRegex, "$1\n$2");
    text = std::regex_replace(text, chineseEllipsisRegex, "$1\n$2");
    text = std::regex_replace(text, endQuotePunctuationRegex, "$1\n$2");

    text.erase(std::remove_if(text.begin(), text.end(), isspace), text.end());
}

// 根据最大长度分割句子
std::vector<std::string> splitSentences(const std::string &text, int maxLength) {
    std::istringstream iss(text);
    std::string sentence;
    std::vector<std::string> sentences;
    while (std::getline(iss, sentence, '\n')) {
        // 检查句子是否为空，若为空则跳过本次循环
        if (sentence.empty()) {
            continue;
        }
        size_t start = 0;
        while (start < sentence.length()) {
            size_t end = std::min(sentence.length(), start + maxLength);
            // 确保不切分多字节字符
            while (end > start && (sentence[end] & 0xC0) == 0x80) {
                --end;
            }
            // 如果end位置没有移动，则向前寻找一个合法的结束位置
            if (end == start) {
                while (start < sentence.length() && (sentence[start] & 0xC0) == 0x80) {
                    ++start;
                }
                end = std::min(sentence.length(), start + maxLength);
                while (end > start && (sentence[end] & 0xC0) == 0x80) {
                    --end;
                }
            }
            sentences.push_back(sentence.substr(start, end - start));
            start = end;
        }
    }
    return sentences;
}


void segmentTokenize(std::vector<std::string> &texts, int maxLength) {
    auto begin = texts.begin();
    while (begin != texts.end()) {
        applyRegex(*begin);
        std::vector<std::string> sentences = splitSentences(*begin, maxLength);
        if (sentences.empty()) {
            ++begin;
            continue;
        }

        begin = texts.erase(begin);
        begin = texts.insert(begin, sentences.begin(), sentences.end());
        std::advance(begin, sentences.size());
    }

}

std::string removeFirstLineWithPrefix(const std::string &input, const std::string &prefix) {
    std::istringstream iss(input);
    std::string line;
    std::vector<std::string> lines;

    bool isFirstLine = true;
    while (std::getline(iss, line)) {
        if (isFirstLine && line.find(prefix) == 0) {
            isFirstLine = false;
            continue;
        }

        lines.push_back(line);
    }

    // 重新构建字符串，去除第一行
    std::ostringstream oss;
    for (const auto &line : lines) {
        oss << line << '\n';
    }

    return oss.str();
}

} // namespace text
